home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 6 / CU Amiga Magazine's Super CD-ROM 06 (1996)(EMAP Images)(GB)(Track 1 of 4)[!][issue 1997-01].iso / cucd / graphics / whirlgif201 / src / whirlgif.c < prev    next >
C/C++ Source or Header  |  1996-11-01  |  18KB  |  817 lines

  1.   
  2. /*
  3.  * whirlgif.c
  4.  *
  5.  * Copyright (C) 1995,1996 by Kevin Kadow (kadokev@msg.net)
  6.  * 
  7.  * Based on txtmerge.c
  8.  * Copyright (C) 1990,1991,1992,1993 by Mark Podlipec. 
  9.  * All rights reserved.
  10.  *
  11.  * This software may be freely copied, modified and redistributed
  12.  * without fee provided that this copyright notice is preserved 
  13.  * intact on all copies and modified copies.
  14.  * 
  15.  * There is no warranty or other guarantee of fitness of this software.
  16.  * It is provided solely "as is". The author(s) disclaim(s) all
  17.  * responsibility and liability with respect to this software's usage
  18.  * or its effect upon hardware or computer systems.
  19.  *
  20.  */
  21. /*
  22.  *  Amiga version by Lars Eilebrecht (sfx@cypberspace.org)
  23.  *                                   (sfx@unix-ag.uni-siegen.de)
  24.  */
  25.  /*
  26.   * Description:
  27.   *
  28.   * This program reads in a sequence of single-image GIF format files and
  29.   * outputs a single multi-image GIF file, suitable for use as an animation.
  30.   *
  31.   * TODO:
  32.   *
  33.   * More options for dealing with the colormap
  34.   *
  35.   * Eventually, I'd like to have this program compare the current image
  36.   * with the previous image and check to see if only a small section of
  37.   * the screen changed from the previous image. Worth a shot.
  38.   */
  39.  
  40.  /*
  41.   * Rev 2.01    31Aug96 Kevin Kadow
  42.   *    disposal
  43.   * Rev 2.00    05Feb96 Kevin Kadow
  44.   *    transparency, gif comments,
  45.   * Rev 1.10    29Jan96 Kevin Kadow
  46.   *    first release of whirlgif
  47.   *
  48.   * txtmerge:
  49.   * Rev 1.00    23Jul91    Mark Podlipec
  50.   *    creation
  51.   * Rev 1.01    08Jan92    Mark Podlipec
  52.   *     use all colormaps, not just 1st.
  53.   *
  54.   * 
  55.   */
  56.  
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #ifdef _USE_STRINGS_H
  60. #include <strings.h>
  61. #else
  62. #include <string.h>
  63. #endif
  64.  
  65. #include "whirlgif.h"
  66.  
  67. #define MAXVAL  4100            /* maxval of lzw coding size */
  68. #define MAXVALP 4200
  69.  
  70.  
  71. static const char ver[]="$VER: WhirlGIF 2.01 (31.08.96) © 1996 by Kevin Kadow, © 1991-1992 by Mark Podlipec (Amiga Version by Lars Eilebrecht)\0";
  72.  
  73. /*
  74.  * Set some defaults, these can be changed on the command line
  75.  */
  76. unsigned int loop=DEFAULT_LOOP,loopcount=0,
  77.     use_colormap=DEFAULT_USE_COLORMAP,
  78.     debug_flag=0,
  79.     verbose=0;
  80.  
  81. int imagex = 0;
  82. int imagey = 0;
  83. int imagec = 0;
  84.  
  85. /* global settings for offset, transparency */
  86. Global global;
  87.  
  88. GIF_Color gif_cmap[256];
  89.  
  90. GIF_Screen_Hdr gifscrn;
  91. GIF_Image_Hdr gifimage;
  92. GIF_Table table[MAXVALP];
  93.  
  94. ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE;
  95. ULONG nextab;
  96. ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0};
  97. ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0};
  98.  
  99.  
  100. UBYTE gif_buff[MAXVALP];
  101. ULONG gif_block_size;
  102. int num_bits,bits;
  103.  
  104. int pic_i;
  105. char gif_file_name[BIGSTRING];
  106. int screen_was_last;
  107.  
  108.  
  109. void TheEnd()
  110. {
  111.  exit(0);
  112. }
  113.  
  114. void TheEnd1(p)
  115. char *p;
  116. {
  117.  fprintf(stderr,"%s",p);
  118.  TheEnd();
  119. }
  120.  
  121. Usage()
  122. {
  123.   fprintf(stderr,"\nUsage: whirlgif\n");
  124.   fprintf(stderr,"         [-v] [-o outfile] [-loop [count]] [-trans index] [-time #delay]\n");
  125.   fprintf(stderr,"         [-disp_none | -disp_back | -disp_prev | -disp_not]\n");
  126.   fprintf(stderr,"         [ -i listfile] file1 [ -time #delay] file2 ...\n");
  127.   exit(0);
  128. }
  129.  
  130. int main(argc,argv)
  131. int argc;
  132. char *argv[];
  133. {
  134.  FILE * infile, *fout;
  135.  char temp[BIGSTRING];
  136.  int i;
  137.  int count=0;
  138.  
  139.  fprintf(stderr,"whirlgif Rev 2.01 (C) 1996 by Kevin Kadow\n");
  140.  fprintf(stderr,"                  (C) 1991,1992 by Mark Podlipec\n");
  141.  
  142.  if (argc < 2) Usage();
  143.  
  144.  /* set global values */
  145.  screen_was_last = FALSE;
  146.  global.trans.type=TRANS_NONE;
  147.  global.trans.valid=FALSE;
  148.  global.time=DEFAULT_TIME;
  149.  global.left=0;
  150.  global.top=0;
  151.  global.disposal=DEFAULT_DISPOSAL;
  152.  
  153.  
  154.  fout=stdout;
  155.  i = 1;
  156.  while( i < argc)
  157.  {
  158.   char *p;
  159.   p = argv[i];
  160.   /*fprintf(stderr,"Option: %s\n",p);*/
  161.   if ( (p[0] == '-') || (p[0] == '+') )
  162.   { 
  163.    ++p; /* strip off the - */
  164.    switch(p[0])
  165.    {
  166.     case 'v':    /* Give lots of information */
  167.             verbose++;
  168.             i++;
  169.         fprintf(stderr,"Verbose output\n");
  170.         break;
  171.  
  172.     case 'd':    /* either Debug mode or disposal setting */
  173.         i++;
  174.         if(!strncmp("disp",p,4)) {
  175.             i++;
  176.             p=argv[1];
  177.             p++;
  178.               if(verbose) fprintf(stderr,"Disposal method set\n");
  179.             if(!strcmp("none",p)) 
  180.                global.disposal = DISP_NONE;
  181.             else if(!strcmp("not",p)) 
  182.                global.disposal = DISP_NOT;
  183.             else if(!strcmp("back",p)) 
  184.                global.disposal = DISP_BACK;
  185.             else if(!strcmp("prev",p)) 
  186.                global.disposal = DISP_PREV;
  187.             else global.disposal = DISP_NONE;
  188.         }
  189.         else {
  190.             debug_flag++;
  191.             fprintf(stderr,"DEBUG: Debug Level %d\n",debug_flag);
  192.         }
  193.         break;
  194.  
  195.     case 'l':    /* Enable looping */
  196.         loop=TRUE;
  197.         i++;
  198.         if(*argv[i] !='-') {
  199.           /* a loop count was given */
  200.           loopcount=atoi(argv[i++]);
  201.           if(verbose) fprintf(stderr,"Loop %d times\n",loopcount);
  202.           }
  203.         else {
  204.           /* default to infinite loop */
  205.           loopcount=0;
  206.           if(verbose) fputs("Looping enabled\n",stderr);
  207.           }
  208.         break;
  209.  
  210.     case 'u':    /* Use colormap? true or false */
  211.         i++;
  212.         if(atoi(argv[i]) || !strcmp("true",argv[i])) use_colormap=1;
  213.         else use_colormap=0;
  214.         i++;
  215.         break;
  216.  
  217.     case 't':    /* either time or transparent */
  218.         i++;
  219.         if(!strcmp("time",p)) {
  220.             /* Delay time in 1/100's of a second */
  221.             global.time=atoi(argv[i++]);
  222.             }
  223.         else if(!strncmp("trans",p,4)) Calc_Trans(argv[i++]);
  224.         break;
  225.  
  226.     case 'o':    /* Output file - send output to a given filename */
  227.         i++;
  228.         if(!strncmp("off",p,3)) set_offset(argv[i]);
  229.         else
  230.         /* It must be 'output, so do that */
  231.         if(NULL==(fout=fopen(argv[i],"w")))
  232.             {
  233.             fprintf(stderr,"Cannot open %s for output\n",argv[i]);
  234.             exit(1);
  235.             }
  236.         i++;
  237.         break;
  238.     case 'i':    /* input file - file with a list of images */
  239.         i++;
  240.         if(NULL != (infile=fopen(argv[i],"r"))) {
  241.             while(fgets(gif_file_name,BIGSTRING,infile)) {
  242.                 strtok(gif_file_name,"\n");
  243.                   if(!count) GIF_Read_File(fout,gif_file_name,1);
  244.                   else       GIF_Read_File(fout,gif_file_name,0);
  245.                   count++;
  246.                 }
  247.             fclose(infile);
  248.             }
  249.         else fprintf(stderr,"Cannot read list file %s\n",argv[i]);
  250.         i++;
  251.         break;
  252.     default: 
  253.         Usage();
  254.         exit(0);
  255.         break;
  256.    }
  257.    continue;
  258.   }
  259.   /* Not an option, must be the name of an input file */
  260.   if(!count) GIF_Read_File(fout,argv[i],1);
  261.   else       GIF_Read_File(fout,argv[i],0);
  262.   count++;
  263.   i++;
  264.  }
  265.  /* We're done with all the options, finish up */
  266.  if(count >0)
  267.   {
  268.   fputc(';',fout); /* image separator */
  269.   sprintf(temp,"whirlgif 2.01 (C) kadokev@msg.net. %d images",count);
  270.   GIF_Comment(fout,temp);
  271.   }
  272.  
  273.  fclose(fout);
  274.  fprintf(stderr,"Processed %d files.\n",count);
  275.  exit(0);
  276. }
  277.  
  278.  
  279. /*
  280.  * Read a GIF file, outputting to fname as we go.
  281.  * It would be faster to read and write the individual blocks,
  282.  * but eventually we'd like to optimize based on changes from
  283.  * previous images(ie only a small section of the image changed.
  284.  */
  285. void
  286. GIF_Read_File(fout,fname,first_image)
  287. FILE * fout;
  288. char *fname;
  289. int first_image;
  290. {
  291.  FILE *fp;
  292.  int i;
  293.  
  294.  if ( (fp=fopen(fname,"r"))==0)
  295.  { 
  296.   fprintf(stderr,"Can't open %s for reading.\n",fname); 
  297.   TheEnd();
  298.  }
  299.  
  300.  GIF_Screen_Header(fp,fout,first_image);
  301.  
  302.  /*** read until  ,  separator */
  303.  do
  304.  {
  305.   i=fgetc(fp);
  306.   if ( (i<0) && feof(fp))
  307.   {
  308.    fclose(fp);
  309.    TheEnd1("GIF_Read_Header: Unexpected End of File\n");
  310.   }
  311.  } while(i != ',');
  312.  
  313.  if(first_image)
  314.   {
  315.    /* stuff we only do once */
  316.    if(loop) GIF_Loop(fout,loopcount);
  317.    }
  318.  if(global.time||(global.trans.type!=TRANS_NONE && global.trans.valid))
  319.     GIF_GCL(fout,global.time);
  320.  
  321.  fputc(',',fout); /* image separator */
  322.  
  323.  GIF_Image_Header(fp,fout,first_image);
  324.  
  325.  /*FOO*/
  326.  
  327.  /*** Setup ACTION for IMAGE */
  328.  
  329.  GIF_Decompress(fp,fout);
  330.  fputc(0,fout);  /* block count of zero */
  331.  
  332.  fclose(fp);
  333. }
  334.  
  335. void GIF_Decompress(fp,fout)
  336. FILE *fp,*fout;
  337. {
  338.  register ULONG code,old;
  339.  
  340.  pic_i = 0;
  341.  bits=0;
  342.  num_bits=0;
  343.  gif_block_size=0;
  344.     /* starting code size of LZW */
  345.  root_code_size=(fgetc(fp) & 0xff); fputc(root_code_size,fout);
  346.  GIF_Clear_Table();                /* clear decoding symbol table */
  347.  
  348.  code=GIF_Get_Code(fp,fout);
  349.  
  350.  if (code==CLEAR) 
  351.  {
  352.   GIF_Clear_Table(); 
  353.   code=GIF_Get_Code(fp,fout);
  354.  }
  355.  /* write code(or what it currently stands for) to file */
  356.  GIF_Send_Data(code);   
  357.  old=code;
  358.  code=GIF_Get_Code(fp,fout);
  359.  do
  360.  {
  361.   if (table[code].valid==1)    /* if known code */
  362.   {
  363.        /* send it's associated string to file */
  364.     GIF_Send_Data(code);
  365.     GIF_Get_Next_Entry(fp);       /* get next table entry (nextab) */
  366.     GIF_Add_To_Table(old,code,nextab);  /* add old+code to table */
  367.     old=code;
  368.   }
  369.   else      /* code doesn't exist */
  370.   {
  371.     GIF_Add_To_Table(old,old,code);   /* add old+old to table */
  372.     GIF_Send_Data(code);
  373.     old=code;
  374.   }
  375.   code=GIF_Get_Code(fp,fout);
  376.   if (code==CLEAR)
  377.   { 
  378.    GIF_Clear_Table();
  379.    code=GIF_Get_Code(fp,fout);
  380.    GIF_Send_Data(code);
  381.    old=code;
  382.    code=GIF_Get_Code(fp,fout);
  383.   }
  384.  } while(code!=EOI);
  385. }
  386.  
  387. void GIF_Get_Next_Entry(fp)
  388. FILE *fp;
  389. {
  390.    /* table walk to empty spot */
  391.  while(  (table[nextab].valid==1)
  392.        &&(nextab<MAXVAL)
  393.       ) nextab++;
  394.  /* 
  395.   * Ran out of space?!  Something's gone sour...
  396.   */
  397.  if (nextab>=MAXVAL)    
  398.  { 
  399.   fprintf(stderr,"Error: GetNext nextab=%d\n",nextab);
  400.   fclose(fp);
  401.   TheEnd();
  402.  }
  403.  if (nextab==INCSIZE)   /* go to next table size (and LZW code size ) */
  404.  {
  405.    /* fprintf(stderr,"GetNext INCSIZE was %d ",nextab); */
  406.    code_size++; INCSIZE=(INCSIZE*2)+1;
  407.    if (code_size>=12) code_size=12;
  408. /*   fprintf(stderr,"<%d>",INCSIZE); */
  409.  }
  410.  
  411. }
  412. /*  body is associated string
  413.     next is code to add to that string to form associated string for
  414.     index
  415. */     
  416.  
  417. void GIF_Add_To_Table(body,next,index)
  418. register ULONG body,next,index;
  419. {
  420.  if (index>MAXVAL)
  421.  { 
  422.   fprintf(stderr,"Error index=%d\n",index);
  423.  }
  424.  else
  425.  {
  426.   table[index].valid=1;
  427.   table[index].data=table[next].first;
  428.   table[index].first=table[body].first;
  429.   table[index].last=body;
  430.  }
  431. }
  432.  
  433. void GIF_Send_Data(index)
  434. register int index;
  435. {
  436.  register int i,j;
  437.  i=0;
  438.  do         /* table walk to retrieve string associated with index */
  439.  { 
  440.   gif_buff[i]=table[index].data; 
  441.   i++;
  442.   index=table[index].last;
  443.   if (i>MAXVAL)
  444.   { 
  445.    fprintf(stderr,"Error: Sending i=%d index=%d\n",i,index);
  446.    TheEnd();
  447.   }
  448.  } while(index>=0);
  449.  
  450.  /* now invert that string since we retreived it backwards */
  451.  i--;
  452.  for(j=i;j>=0;j--)
  453.  {
  454.   /*pic[pic_i] = gif_buff[j] | gif_pix_offset;*/
  455.   pic_i++;
  456.  }
  457. }
  458.  
  459.  
  460. /* 
  461.  * initialize string table 
  462.  */
  463. void GIF_Init_Table()       
  464. {
  465.  register int maxi,i;
  466.  
  467. if (debug_flag) fprintf(stderr,"Initing Table...");
  468.  maxi=gif_ptwo[root_code_size];
  469.  for(i=0; i<maxi; i++)
  470.  {
  471.   table[i].data=i;   
  472.   table[i].first=i;
  473.   table[i].valid=1;  
  474.   table[i].last = -1;
  475.  }
  476.  CLEAR=maxi; 
  477.  EOI=maxi+1; 
  478.  nextab=maxi+2;
  479.  INCSIZE = (2*maxi)-1;
  480.  code_size=root_code_size+1;
  481. }
  482.  
  483.  
  484. /* 
  485.  * clear table 
  486.  */
  487. void GIF_Clear_Table()   
  488. {
  489.  register int i;
  490. if (debug_flag) fprintf(stderr,"Clearing Table...\n");
  491.  for(i=0;i<MAXVAL;i++) table[i].valid=0;
  492.  GIF_Init_Table();
  493. }
  494.  
  495. /*CODE*/
  496. ULONG GIF_Get_Code(fp,fout) /* get code depending of current LZW code size */
  497. FILE *fp,*fout;
  498. {
  499.  ULONG code;
  500.  register int tmp;
  501.  
  502.  while(num_bits < code_size)
  503.  {
  504.   /**** if at end of a block, start new block */
  505.   if (gif_block_size==0) 
  506.   {
  507.    tmp = fgetc(fp);
  508.    if (tmp >= 0 )
  509.    {
  510.     fputc(tmp,fout);
  511.     gif_block_size=(ULONG)(tmp);
  512.    }
  513.    else TheEnd1("EOF in data stream\n");
  514.   }
  515.  
  516.   tmp = fgetc(fp);   gif_block_size--;
  517.   if (tmp >= 0)
  518.   {
  519.    fputc(tmp,fout);
  520.    bits |= ( ((ULONG)(tmp) & 0xff) << num_bits );
  521.    num_bits+=8;
  522.   }
  523.   else TheEnd1("EOF in data stream\n");
  524.  }
  525.   
  526.  code = bits & gif_mask[code_size];
  527.  bits >>= code_size;
  528.  num_bits -= code_size; 
  529.  
  530.  
  531.  if (code>MAXVAL)
  532.  { 
  533.   fprintf(stderr,"\nError! in stream=%x \n",code); 
  534.   fprintf(stderr,"CLEAR=%x INCSIZE=%x EOI=%x code_size=%x \n",
  535.                                            CLEAR,INCSIZE,EOI,code_size); 
  536.   code=EOI;
  537.  }
  538.  
  539.  if (code==INCSIZE)
  540.  {
  541.   if (code_size<12)
  542.   {
  543.    code_size++; INCSIZE=(INCSIZE*2)+1;
  544.   }
  545.   else if (debug_flag) fprintf(stderr,"<13?>"); 
  546.  }
  547.  
  548.  return(code);
  549. }
  550.  
  551.  
  552. /* 
  553.  * read GIF header 
  554.  */
  555. void GIF_Screen_Header(fp,fout,first_time)
  556. FILE *fp,*fout;
  557. int first_time;
  558. {
  559.  int temp,i;
  560.  
  561.  for(i=0;i<6;i++)
  562.  {
  563.   temp = fgetc(fp);
  564.   if(i==4 && temp == '7') temp='9';
  565.   if (first_time==TRUE) fputc(temp,fout);
  566.  }
  567.  
  568.  gifscrn.width  = GIF_Get_Short(fp,fout,first_time);
  569.  gifscrn.height = GIF_Get_Short(fp,fout,first_time);
  570.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  571.  gifscrn.m       =  temp & 0x80;
  572.  gifscrn.cres    = (temp & 0x70) >> 4;
  573.  gifscrn.pixbits =  temp & 0x07;
  574.  
  575.  gifscrn.bc  = fgetc(fp);
  576.  if (first_time==TRUE) 
  577.     {
  578.     /* we really should set the background color to the transparent color */
  579.     fputc(gifscrn.bc,fout);
  580.     }
  581.  
  582.  temp=fgetc(fp);                 if (first_time==TRUE) fputc(temp,fout);
  583.  imagec=gif_ptwo[(1+gifscrn.pixbits)];
  584.  
  585.  if (verbose)
  586.   fprintf(stderr,"Screen: %dx%dx%d m=%d cres=%d bkgnd=%d pix=%d\n",
  587.     gifscrn.width,gifscrn.height,imagec,gifscrn.m,gifscrn.cres,
  588.     gifscrn.bc,gifscrn.pixbits);
  589.  
  590.  if(global.trans.type==TRANS_RGB) global.trans.valid=0;
  591.  if (gifscrn.m)
  592.  {
  593.   for(i=0;i<imagec;i++)
  594.   {
  595.    gif_cmap[i].cmap.red   = temp = fgetc(fp); 
  596.            if (first_time==TRUE) fputc(temp,fout);
  597.    gif_cmap[i].cmap.green = temp = fgetc(fp); 
  598.            if (first_time==TRUE) fputc(temp,fout);
  599.    gif_cmap[i].cmap.blue  = temp = fgetc(fp); 
  600.            if (first_time==TRUE) fputc(temp,fout);
  601.  
  602.    if(global.trans.type==TRANS_RGB && !global.trans.valid)
  603.     if(global.trans.red==gif_cmap[i].cmap.red &&
  604.     global.trans.green==gif_cmap[i].cmap.green &&
  605.     global.trans.blue==gif_cmap[i].cmap.blue) {
  606.       if(debug_flag>1) fprintf(stderr," Transparent match at %d\n",i);
  607.         global.trans.map=i;
  608.     global.trans.valid=TRUE;
  609.     }
  610.   }
  611.  }
  612.  screen_was_last = TRUE;
  613. }
  614.  
  615. void GIF_Image_Header(fp,fout,first_time)
  616. FILE *fp,*fout;
  617. int first_time;
  618. {
  619.  int temp,tnum,i,r,g,b;
  620.  
  621.  gifimage.left   = GIF_Get_Short(fp,fout,1);
  622.  if(global.left) gifimage.left+=global.left;
  623.  
  624.  gifimage.top    = GIF_Get_Short(fp,fout,1);
  625.  if(global.top) gifimage.top+=global.top;
  626.  
  627.  gifimage.width  = GIF_Get_Short(fp,fout,1);
  628.  gifimage.height = GIF_Get_Short(fp,fout,1);
  629.  temp=fgetc(fp); 
  630.  
  631.  
  632.     
  633.  gifimage.i        = temp & 0x40;
  634.  gifimage.pixbits  = temp & 0x07;
  635.  gifimage.m        = temp & 0x80;
  636.  
  637.  /* this sets the local colormap bit to true */
  638.  if (screen_was_last && (first_time==FALSE)) temp |= 0x80;
  639.  
  640.  temp &= 0xf8;
  641.  temp |= gifscrn.pixbits;
  642.  fputc(temp,fout);
  643.  
  644.  imagex=gifimage.width;
  645.  imagey=gifimage.height;
  646.  tnum=gif_ptwo[(1+gifimage.pixbits)];
  647.  if (verbose)
  648.   fprintf(stderr,"Image: %dx%dx%d (%d,%d) m=%d i=%d pix=%d \n",
  649.     imagex,imagey,tnum,gifimage.left,gifimage.top,
  650.     gifimage.m,gifimage.i,gifimage.pixbits);
  651.  
  652.  /* if there is an image cmap, then use it */
  653.  
  654.  if (gifimage.m)
  655.  {
  656.   if(debug_flag) fprintf(stderr,"DEBUG:Transferring colormap of %d colors\n",
  657.             imagec);
  658.   for(i=0;i<tnum;i++)
  659.   {
  660.    gif_cmap[i].cmap.red   = r = fgetc(fp);
  661.    gif_cmap[i].cmap.green = g = fgetc(fp);
  662.    gif_cmap[i].cmap.blue  = b = fgetc(fp);
  663.    fputc(r,fout);
  664.    fputc(g,fout);
  665.    fputc(b,fout);
  666.   }
  667.  }  /* else if screen was last not 1st time */
  668.  else if (screen_was_last && (first_time==FALSE))
  669.  {
  670.   if(debug_flag>1) fprintf(stderr,"DEBUG:Writing colormap of %d colors\n",
  671.             imagec);
  672.   for(i=0;i<imagec;i++)
  673.   {
  674.    fputc(gif_cmap[i].cmap.red  ,fout);
  675.    fputc(gif_cmap[i].cmap.green,fout);
  676.    fputc(gif_cmap[i].cmap.blue ,fout);
  677.   }
  678.  }
  679.  screen_was_last = FALSE; 
  680. }
  681.  
  682.  
  683. /*
  684.  *
  685.  */
  686. int GIF_Get_Short(fp,fout,first_time)
  687. FILE *fp,*fout;
  688. int first_time;
  689. {
  690.  register int temp,tmp1;
  691.  temp=fgetc(fp);     if (first_time==TRUE) fputc(temp,fout);
  692.  tmp1=fgetc(fp);     if (first_time==TRUE) fputc(tmp1,fout);
  693.  return(temp|( (tmp1) << 8 ));
  694. }
  695.  
  696. void GIF_Comment(fout,string)
  697. FILE *fout;
  698. char *string;
  699. {
  700. if(!string || !strlen(string))
  701.         {
  702.         /* Bogus string */
  703.         if(debug_flag) fprintf(stderr,"GIF_Comment: invalid argument");
  704.         return;
  705.         }
  706. fputc(0x21,fout);
  707. fputc(0xFE,fout);
  708. fputs(string,fout);
  709. fputc(0,fout);
  710. }
  711.  
  712. /*
  713.  * Write a Netscape loop marker.
  714.  */
  715. void GIF_Loop(fout,repeats)
  716. FILE *fout;
  717. unsigned int repeats;
  718. {
  719. UBYTE low=0,high=0;
  720. if(repeats) {
  721.     /* non-zero repeat count- Netscape hasn't implemented this yet */
  722.     high=repeats / 256;
  723.     low=repeats % 256;
  724.     }
  725.  
  726. fputc(0x21,fout);
  727. fputc(0xFF,fout);
  728. fputc(0x0B,fout);
  729. fputs("NETSCAPE2.0",fout);
  730. fputc(0x03,fout);
  731. fputc(0x01,fout);
  732.  
  733. fputc(low,fout); /* the delay count - 0 for infinite */
  734. fputc(high,fout); /* second byte of delay count */
  735. fputc(0x00,fout); /* terminator */
  736.  
  737. if(verbose) fprintf(stderr,"Wrote loop extension\n");
  738. }
  739.  
  740. /*
  741.  * GIF_GCL - add a Control Label to set an inter-frame delay value.
  742.  */
  743. void GIF_GCL(fout,delay)
  744. FILE * fout;
  745. unsigned int delay;
  746. {
  747. UBYTE low=0,high=0,flag;
  748. if(delay) {
  749.     /* non-zero delay, figure out low/high bytes */
  750.     high=delay / 256;
  751.     low=delay % 256;
  752.     }
  753.  
  754. fputc(0x21,fout);
  755. fputc(0xF9,fout);
  756. fputc(0x04,fout);
  757.  
  758. flag = global.disposal <<2;
  759. if(delay) flag |=0x80;
  760. if(global.trans.valid) flag |=0x01;
  761. fputc(flag,fout);
  762.  
  763. fputc(low,fout); /* the delay speed - 0 is instantaneous */
  764. fputc(high,fout); /* second byte of delay count */
  765.  
  766. fputc(global.trans.map,fout);
  767. fputc(0,fout);
  768. if(debug_flag>1) {
  769.   fprintf(stderr,"GCL: delay %d",delay);
  770.   if(global.trans.valid) fprintf(stderr," Transparent: %d",global.trans.map);
  771.   fputc('\n',stderr);
  772.   }
  773. }
  774.  
  775.  
  776. void Calc_Trans(string)
  777. char * string;
  778. {
  779. if(string[0] != '#') {
  780.   global.trans.type=TRANS_MAP;
  781.   global.trans.map=atoi(string);
  782.   global.trans.valid=1;
  783.   }
  784. else
  785.   {
  786.   /* it's an RGB value */
  787.   int r,g,b;
  788.   string++;
  789.   if(3==sscanf(string,"%2x%2x%2x",&r,&g,&b)) {
  790.     global.trans.red=r;
  791.     global.trans.green=g;
  792.     global.trans.blue=b;
  793.     global.trans.type=TRANS_RGB;
  794.     if(debug_flag) fprintf(stderr,"Transparent RGB=(%x,%x,%x)\n",r,g,b);
  795.     }
  796.   }
  797. if(debug_flag) fprintf(stderr,"DEBUG:Calc_trans is %d\n",global.trans.type);
  798. }
  799.  
  800. void set_offset(string)
  801. char * string;
  802. {
  803. char *off_x,*off_y;
  804. off_x=(char *) strtok(string,",");
  805. off_y=(char *)strtok((char *)NULL,",");
  806. if(off_x && off_y) {
  807.     /* set the offset */
  808.     global.left=atoi(off_x);
  809.     global.top=atoi(off_y);
  810.     if(debug_flag>1) fprintf(stderr,"Offset changed to %d,%d\n",
  811.         global.left,global.top);
  812.     return;
  813.     }
  814. if(debug_flag>1) fprintf(stderr,"Couldn't parse offset values.\n");
  815. exit(1);
  816. }
  817.